﻿// //  ********************************************************************************
// //  Copyright (C) 2016 Sebastian Kenter. All rights reserved.
// // 
// //  Name    : MultiServerEngine | LoginServer | AccountLoginRequestHandler.cs
// //  Created : 2016 - 02 - 16 20:53
// //  Modified: 2016 - 02 - 20 12:33
// //  ********************************************************************************

using System.Collections.Generic;
using ExitGames.Logging;
using LoginServer.Operations;
using NHibernate;
using ServerFramework.Implementation.Database;
using ServerFramework.Implementation.Database.Domain;
using ServerFramework.Implementation.Handler;
using ServerFramework.Implementation.Server;
using ServerFramework.Implementation.Telegram;
using ServerFramework.Interfaces.Server;
using ServerFramework.Interfaces.Telegram;
using TypeDefs;

namespace LoginServer.Handler.Request
{
    public class AccountLoginRequestHandler : ServerTelegramHandler
    {
        public override TelegramHandlerTypes HandlerType => TelegramHandlerTypes.Request;
        public override byte Code => (byte) OperationCodes.Login;
        public override int? SubCode => (int?) OperationSubCodes.LoginAccount;

        public AccountLoginRequestHandler(ILogger logger) : base(logger)
        {
        }

        public override bool HandleTelegram(ITelegram telegram, IServerPeer serverPeer)
        {
            bool handled = false;

            Logger.InfoFormat(
                "Trying to handle telegram of type={0}, code={1}, sub-code={2} from server={3} for client={4}",
                telegram.Type,
                telegram.Code, telegram.SubCode, telegram.Parameters[(byte) ParameterCodes.PeerType],
                telegram.Parameters[(byte) ParameterCodes.PeerId]);

            ServerPeer peer = serverPeer as ServerPeer;

            if (peer != null)
            {
                LoginAccountRequestOperation contract = new LoginAccountRequestOperation(peer.Protocol, telegram);

                if (contract.IsValid)
                {
                    using (ISession session = SessionManager.OpenSession())
                    {
                        using (ITransaction transaction = session.BeginTransaction())
                        {
                            IList<Account_T> accounts =
                                session.QueryOver<Account_T>()
                                    .Where(c => c.Email == contract.Username).List<Account_T>();

                            if (accounts.Count > 0 && accounts.Count < 2)
                            {
                                Account_T account = accounts[0];

                                Logger.InfoFormat("Account for user {0} found", contract.Username);

                                if (SecurityHelper.ValidatePassword(contract.Password, account.Salt))
                                {
                                    peer.SendTelegram(new ResponseTelegram(telegram.Code, telegram.SubCode,
                                        telegram.Parameters,
                                        (short) ReturnCodes.AccountLoggedIn,
                                        EnumHelper.GetEnumDescription(ReturnCodes.AccountLoggedIn)));
                                }
                                else
                                {
                                    Logger.WarnFormat("Credentials not valid.");

                                    account.Loginfailures += 1;

                                    session.Update(account);

                                    peer.SendTelegram(new ResponseTelegram(telegram.Code, telegram.SubCode,
                                        telegram.Parameters,
                                        (short) ErrorCodes.InvalidCredentials,
                                        EnumHelper.GetEnumDescription(ErrorCodes.InvalidCredentials)));
                                }

                                transaction.Commit();
                                handled = true;
                            }
                            else
                            {
                                Logger.InfoFormat("Account for user {0} not found", contract.Username);

                                peer.SendTelegram(new ResponseTelegram(telegram.Code, telegram.SubCode,
                                    telegram.Parameters,
                                    (short) ErrorCodes.NoAccountFound,
                                    EnumHelper.GetEnumDescription(ErrorCodes.NoAccountFound)));

                                transaction.Commit();
                                handled = true;
                            }
                        }
                    }
                }
            }

            return handled;
        }
    }
}
